package com.octopus.tree.imp.simple;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.apache.log4j.Logger;

import com.octopus.string.StringUtils;
import com.octopus.tree.TreeBranch;
import com.octopus.tree.TreeLeaf;
import com.octopus.tree.structure.NType;
import com.octopus.tree.structure.NodeType;
import com.octopus.tree.structure.XpType;

public class TreeBranchImp extends NType implements TreeBranch, Cloneable, Serializable {

	private static final Logger logger = Logger.getLogger(TreeBranchImp.class.getName());
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private Boolean initProperties_flag = new Boolean(false);
	private Properties properties = new Properties();
	
	Boolean treeLeaf_initflag = new Boolean(false);
	private List<TreeLeaf> treeLeafList = new ArrayList<TreeLeaf>();
	private Map<String, TreeLeaf> treeLeafOneMap = new HashMap<String, TreeLeaf>();
	private Map<String, List<TreeLeaf>> treeLeafManyMap = new HashMap<String, List<TreeLeaf>>();
	
	private Boolean treeBranch_initflag = new Boolean(false);
	private List<TreeBranch> treeBranchList = new ArrayList<TreeBranch>();
	private Map<String, TreeBranch> treeBranchOneMap = new HashMap<String, TreeBranch>();	
	private Map<String, List<TreeBranch>> treeBranchManyMap = new HashMap<String, List<TreeBranch>>();

	private TreeBranchImp parent;
	
	public TreeBranchImp getParent() {
		return parent;
	}

	protected synchronized void setParent(TreeBranchImp parent) {
		this.parent = parent;
	}

	private TreeBranchImp() {
	}
	
	public TreeBranchImp(String name, String kind, Properties properties) {
		this();
		this.setName(name);
		this.setKind(kind);
		if(properties != null && !properties.isEmpty()){
			Set<Object> keySet = properties.keySet();
			Iterator<Object> keyIterator = keySet.iterator();
			while(keyIterator.hasNext()){
				String key = (String)keyIterator.next();
				String value = properties.getProperty(key);
				this.setTreeBranchProperty(key, value);
			}
		}
	}
	
	public TreeBranchImp(NType nType) throws NameAlreadyExistException, AlreadyInTreeStructureException{
		this();
		if(nType != null){
			this.setKind(nType.getKind());
			this.setName(nType.getName());
			this.getXp().addAll(nType.getXp());
			for(NType ntype : nType.getN()){
				TreeBranchImp ntypeNew = new TreeBranchImp(ntype);
				this.addTreeBranch(ntypeNew);
			}
			for(NodeType nodetype : nType.getNode()){
				TreeLeafImp nodetypeNew = new TreeLeafImp(nodetype);
				this.addTreeLeaf(nodetypeNew);
			}
		}
	}
	
	private void initProperties(){
		synchronized(initProperties_flag){
			if(!initProperties_flag){
				List<XpType> propertiesList = this.getXp();
				if(propertiesList != null){
					for(XpType xt : propertiesList){
						properties.setProperty(xt.getKey(), xt.getValue());
					}
				}
				initProperties_flag = new Boolean(true);
			}
		}
	}

	@Override
	public Properties getTreeBranchProperties() {
		if(!this.initProperties_flag){
			initProperties();
		}
		Properties properties = new Properties();
		properties.putAll(this.properties);
		return properties;
	}
	
	@Override
	public String getTreeBranchProperty(String key){
		if(!this.initProperties_flag){
			initProperties();
		}
		return this.properties.getProperty(key);
	}
	
	protected void setSystemTreeBranchProperty(String key, String value){
		setTreeBranchPropertyInternal(key, value);
	}
	
	@Override
	public void setTreeBranchProperty(String key, String value){
		if(key != null && !key.startsWith(SimpleImpConstants.SYSTEM_PROPERTY_ROOT)){
			setTreeBranchPropertyInternal(key, value);
		}
	}
	
	private void setTreeBranchPropertyInternal(String key, String value){
		if(key == null){
			return;
		}
		if(!this.initProperties_flag){
			initProperties();
		}
		this.properties.setProperty(key, value);
		List<XpType> xpList = this.getXp();
		boolean alreadyExist = false;
		for(XpType xt : xpList){
			if(key.equals(xt.getKey())){
				alreadyExist = true;
				xt.setValue(value);
			}
		}
		if(!alreadyExist){
			XpType xt = new XpType();
			xt.setKey(key);
			xt.setValue(value);
			xpList.add(xt);
		}
	}
	
	@Override
	public void removeTreeBranchProperty(String key){
		if(!this.initProperties_flag){
			initProperties();
		}
		this.properties.remove(key);
		List<XpType> xpList = this.getXp();
		for(int i = xpList.size(); i >= 0 ; i--){
			XpType xt = xpList.get(i);
			if(key.equals(xt.getKey())){
				xpList.remove(i);
			}
		}
	}
	
	
	private void initDataTreeLeaf(){
		synchronized(this.treeLeaf_initflag){
			if(!treeLeaf_initflag){
				List<NodeType> nodeList = this.getNode();
				this.treeLeafOneMap.clear();
				this.treeLeafManyMap.clear();
				for(NodeType nt : nodeList){
					if(nt instanceof TreeLeafImp){
						boolean isDefault = (((TreeLeafImp)nt).getKind() == null);
						if(isDefault && this.treeLeafOneMap.containsKey(nt.getName())){
							logger.fatal(StringUtils.concat("Duplicated NodeType name is found [",nt.getName(),"]"));
							continue;
						}
						if(isDefault){
							this.treeLeafOneMap.put(nt.getName(), (TreeLeafImp)nt);
						}
						this.treeLeafList.add((TreeLeafImp)nt);
						List<TreeLeaf> treeLeafMany = this.treeLeafManyMap.get(nt.getName());
						if(treeLeafMany == null){
							treeLeafMany = new ArrayList<TreeLeaf>();
							treeLeafMany.add((TreeLeafImp)nt);
							this.treeLeafManyMap.put(nt.getName(), treeLeafMany);
						}else{
							treeLeafMany.add((TreeLeafImp)nt);
						}
					}else{
						logger.fatal(StringUtils.concat(String.valueOf(nt.getName()), " is not an instance of TreeLeafImp"));
					}
				}
				this.treeLeaf_initflag = new Boolean(true);
			}
		}
	}

	@Override
	public List<TreeLeaf> getTreeLeafList() {
		if(!treeLeaf_initflag){
			initDataTreeLeaf();	
		}
		return this.treeLeafList;
	}
	
	@Override
	public List<TreeLeaf> getDefaultTreeLeafList(){
		if(!treeLeaf_initflag){
			initDataTreeLeaf();	
		}
		List<TreeLeaf> result = new ArrayList<TreeLeaf>();
		result.addAll(this.treeLeafOneMap.values());
		return result;
	}

	@Override
	public TreeLeaf getDefaultTreeLeafByName(String name) {
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		return this.treeLeafOneMap.get(name);
	}
	
	@Override
	public List<TreeLeaf> getTreeLeafByName(String name) {
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		List<TreeLeaf> result = new ArrayList<TreeLeaf>();
		List<TreeLeaf> temp = this.treeLeafManyMap.get(name);
		if(temp != null && !temp.isEmpty()){
			result.addAll(temp);
		}
		return result;
	}

	@Override
	public List<TreeLeaf> getTreeLeafByNameAndKind(String name, String kind) {		
		List<TreeLeaf> intermediateResult = getTreeLeafByName(name);
		if(StringUtils.isNullString(kind)){
			return intermediateResult;
		}
		kind = kind.trim();
		for(int i = intermediateResult.size() ; i >= 0 ; i--){
			NodeType nt = (TreeLeafImp)intermediateResult.get(i);
			if(!kind.equals(nt.getKind())){
				intermediateResult.remove(i);
			}
		}
		return intermediateResult;
	}
	
	@Override
	public boolean addTreeLeaf(TreeLeaf treeLeaf) throws AlreadyInTreeStructureException, NameAlreadyExistException{
		if(treeLeaf == null){
			return false;
		}		
		TreeLeafImp tli = (TreeLeafImp)treeLeaf;
		if(tli.getParent() != null){
			throw new AlreadyInTreeStructureException(StringUtils.concat( "LEAF[",tli.genTreePath(),"]INTO[" + genTreePath() + "]"));
		}
		if(treeLeaf.getTreeLeafName() == null){
			return false;
		}
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		boolean isDefault = (tli.getKind() == null);
		if(isDefault){
			synchronized(treeLeaf_initflag){
				if(treeLeafOneMap.containsKey(tli.getName())){
					throw new NameAlreadyExistException(StringUtils.concat("["+tli.getName()+"] already exists in ["+this.genTreePath()+"]"));
				}
				this.treeLeafOneMap.put(tli.getName(), tli);
				List<TreeLeaf> treeLeafList = this.treeLeafManyMap.get(tli.getName());
				if(treeLeafList == null){
					treeLeafList = new ArrayList<TreeLeaf>();
					this.treeLeafManyMap.put(tli.getName(), treeLeafList);
				}
				if(this.treeLeafList.contains(tli)){
					tli.setParent(this);
					return false;
				}
				treeLeafList.add(tli);
				this.treeLeafList.add(tli);
				this.getNode().add(tli);
				tli.setParent(this);
			}
		}else{
			synchronized(treeLeaf_initflag){
				List<TreeLeaf> treeLeafList = this.treeLeafManyMap.get(tli.getName());
				if(treeLeafList == null){
					treeLeafList = new ArrayList<TreeLeaf>();
					this.treeLeafManyMap.put(tli.getName(), treeLeafList);
				}
				if(this.treeLeafList.contains(tli)){
					this.setParent(this);
					return false;
				}
				treeLeafList.add(tli);
				this.treeLeafList.add(tli);
				this.getNode().add(tli);
				tli.setParent(this);
			}
		}
		tli.setParent(this);
		return true;
	}
	
	@Override
	public void removeTreeLeaf(TreeLeaf treeLeaf){
		if(treeLeaf == null){
			return;
		}		
		TreeLeafImp tli = (TreeLeafImp)treeLeaf;
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		boolean isDefault = (tli.getKind() == null);
		if(isDefault){
			synchronized(treeLeaf_initflag){
				if(treeLeafOneMap.containsKey(tli.getName())){
					treeLeafOneMap.remove(tli.getName());
				}
				List<TreeLeaf> treeLeafList = this.treeLeafManyMap.get(tli.getName());
				if(treeLeafList == null){
					treeLeafList = new ArrayList<TreeLeaf>();
					this.treeLeafManyMap.put(tli.getName(), treeLeafList);
				}
				if(treeLeafList.contains(tli)){
					treeLeafList.remove(tli);
				}
				this.treeLeafList.remove(tli);
				this.getNode().remove(tli);
			}
		}else{
			synchronized(treeLeaf_initflag){
				List<TreeLeaf> treeLeafList = this.treeLeafManyMap.get(tli.getName());
				if(treeLeafList == null){
					treeLeafList = new ArrayList<TreeLeaf>();
					this.treeLeafManyMap.put(tli.getName(), treeLeafList);
				}
				if(treeLeafList.contains(tli)){
					treeLeafList.remove(tli);
				}
				this.treeLeafList.remove(tli);
				this.getNode().remove(tli);
			}
		}
		((TreeLeafImp)treeLeaf).setParent(null);
	}
	
	private void initDataTreeBranch(){
		synchronized(this.treeBranch_initflag){
			if(!treeBranch_initflag){
				List<NType> nList = this.getN();
				this.treeBranchList.clear();
				this.treeBranchOneMap.clear();
				this.treeBranchManyMap.clear();
				for(NType nt : nList){
					boolean isDefault = (((TreeBranchImp)nt).getKind() == null);
					if(isDefault && this.treeBranchOneMap.containsKey(nt.getName())){
						logger.fatal(StringUtils.concat("Duplicated NType name is found [",nt.getName(),"]"));
						continue;
					}
					if(isDefault){
						this.treeBranchOneMap.put(nt.getName(), (TreeBranchImp)nt);
					}
					this.treeBranchList.add((TreeBranchImp)nt);
					List<TreeBranch> treeBranchMany = this.treeBranchManyMap.get(nt.getName());
					if(treeBranchMany == null){
						treeBranchMany = new ArrayList<TreeBranch>();
						treeBranchMany.add((TreeBranchImp)nt);
						this.treeBranchManyMap.put(nt.getName(), treeBranchMany);
					}else{
						treeBranchMany.add((TreeBranchImp)nt);
					}
				}
				this.treeBranch_initflag = new Boolean(true);
			}
		}
	}
	
	@Override
	public List<TreeBranch> getAllSubBranch(){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		return this.treeBranchList;
	}
	
	@Override
	public List<TreeBranch> getDefaultAllSubBranch(){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		List<TreeBranch> result = new ArrayList<TreeBranch>();
		result.addAll(treeBranchOneMap.values());
		return result;
	}
	
	@Override
	public TreeBranch getDefaultSubTreeBrancByName(String name){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		return this.treeBranchOneMap.get(name);
	}
	
	@Override
	public List<TreeBranch> getSubTreeBranchListByName(String name){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		List<TreeBranch> result = new ArrayList<TreeBranch>();
		List<TreeBranch> temp = this.treeBranchManyMap.get(name);
		if(temp != null && !temp.isEmpty()){
			result.addAll(temp);
		}		
		return result;
	}
	
	@Override
	public List<TreeBranch> getSubTreeBranchListByNameAndKind(String name, String kind){
		List<TreeBranch> branchList = getSubTreeBranchListByName(name);
		if(StringUtils.isNullString(kind)){
			return branchList;
		}
		kind = kind.trim();
		for(int i = branchList.size(); i >= 0 ; i--){
			TreeBranchImp tbi = (TreeBranchImp)branchList.get(i);
			if(!kind.equals(tbi.getKind())){
				branchList.remove(i);
			}
		}
		return branchList;
	}
	
	@Override
	public boolean addTreeBranch(TreeBranch treeBranch) throws NameAlreadyExistException, AlreadyInTreeStructureException{
		if(treeBranch == null){
			return false;
		}		
		TreeBranchImp tbi = (TreeBranchImp)treeBranch;
		if(tbi.getParent() != null){
			throw new AlreadyInTreeStructureException(StringUtils.concat("BRANCH[",tbi.genTreePath(),"]INTO[",genTreePath(),"]"));
		}
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		if(treeBranch.getTreeBranchName() == null){
			return false;
		}
		boolean isDefault = (tbi.getKind() == null);
		if(isDefault){
			synchronized(treeBranch_initflag){
				if(treeBranchOneMap.containsKey(tbi.getName())){
					throw new NameAlreadyExistException(StringUtils.concat("["+tbi.getName()+"] already exist"));
				}
				this.treeBranchOneMap.put(tbi.getName(), tbi);
				List<TreeBranch> treeBranchList = this.treeBranchManyMap.get(tbi.getName());
				if(treeBranchList == null){
					treeBranchList = new ArrayList<TreeBranch>();
					this.treeBranchManyMap.put(tbi.getName(), treeBranchList);
				}
				if(this.treeBranchList.contains(tbi)){
					tbi.setParent(this);
					return false;
				}
				treeBranchList.add(tbi);
				this.treeBranchList.add(tbi);
				this.getN().add(tbi);
			}
		}else{
			synchronized(treeBranch_initflag){
				List<TreeBranch> treeBranchList = this.treeBranchManyMap.get(tbi.getName());
				if(treeBranchList == null){
					treeBranchList = new ArrayList<TreeBranch>();
					this.treeBranchManyMap.put(tbi.getName(), treeBranchList);
				}
				if(this.treeBranchList.contains(tbi)){
					tbi.setParent(this);
					return false;
				}
				treeBranchList.add(tbi);
				this.treeBranchList.add(tbi);
				this.getN().add(tbi);
			}
		}
		tbi.setParent(this);
		return true;
	}
	
	@Override
	public void removeTreeBranch(TreeBranch treeBranch){
		if(treeBranch == null){
			return;
		}		
		TreeBranchImp tbi = (TreeBranchImp)treeBranch;
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		boolean isDefault = (tbi.getKind() == null);
		if(isDefault){
			synchronized(treeBranch_initflag){
				if(treeBranchOneMap.containsKey(tbi.getName())){
					treeBranchOneMap.remove(tbi.getName());
				}
				List<TreeBranch> treeBranchList = this.treeBranchManyMap.get(tbi.getName());
				if(treeBranchList == null){
					treeBranchList = new ArrayList<TreeBranch>();
					this.treeBranchManyMap.put(tbi.getName(), treeBranchList);
				}
				if(treeBranchList.contains(tbi)){
					treeBranchList.remove(tbi);
				}
				this.treeBranchList.remove(tbi);
				this.getN().remove(tbi);
			}
		}else{
			synchronized(treeBranch_initflag){
				List<TreeBranch> treeBranchList = this.treeBranchManyMap.get(tbi.getName());
				if(treeBranchList == null){
					treeBranchList = new ArrayList<TreeBranch>();
					this.treeBranchManyMap.put(tbi.getName(), treeBranchList);
				}
				if(treeBranchList.contains(tbi)){
					treeBranchList.remove(tbi);
				}
				this.treeBranchList.remove(tbi);
				this.getN().remove(tbi);
			}
		}
		((TreeBranchImp)(treeBranch)).setParent(null);
	}
	
	@Override
	public String genTreePath(){
		String parentPath = genParentPath();
		if(parentPath.isEmpty()){
			return this.getName();
		}else{
			return StringUtils.concat(parentPath, ".", this.getName());
		}
	}
	
	@Override
	public String genParentPath(){
		String path = "";
		TreeBranchImp parent = this.parent;
		int i = 0 ;
		while(parent != null){
			if(SimpleUtils.isRootBranch(parent)){
				break;
			}
			if(i == 0){
				path = parent.getName();
			}else{
				path = StringUtils.concat(parent.getName() ,".", path);
			}
			parent = parent.getParent();
			i++;
		}
		return path;
	}
	
	@Override
	public String getTreeBranchKind(){
		return this.getKind();
	}

	@Override
	public boolean preparePermanent() {
		boolean result = true;
		List<TreeLeaf> treeLeafList = getTreeLeafList();
		for(TreeLeaf tl : treeLeafList){
			if(!tl.preparePermanent()){
				logger.error(StringUtils.concat("PreparePermanent TreeLeaf failed[",tl.genTreePath(),"]"));
				result = false; 
			}
		}
		List<TreeBranch> treeBranchList = this.getAllSubBranch();
		for(TreeBranch tb : treeBranchList){
			if(!tb.preparePermanent()){
				logger.error(StringUtils.concat("PreparePermanent TreeBranch failed[",tb.genTreePath(),"]"));
				result = false;
			}
		}
		return result;
	}

	@Override
	public void clearPermanent() {
		List<TreeLeaf> treeLeafList = getTreeLeafList();
		for(TreeLeaf tl : treeLeafList){
			tl.clearPermanent();
		}
		List<TreeBranch> treeBranchList = this.getAllSubBranch();
		for(TreeBranch tb : treeBranchList){
			tb.clearPermanent();
		}
	}

	@Override
	public boolean toContentObject() {
		boolean result = true;
		List<TreeLeaf> treeLeafList = getTreeLeafList();
		for(TreeLeaf tl : treeLeafList){
			if(!tl.toContentObject()){
				logger.error(StringUtils.concat("To ContentObject TreeLeaf failed[",tl.genTreePath(),"]"));
				result = false; 
			}
		}
		List<TreeBranch> treeBranchList = this.getAllSubBranch();
		for(TreeBranch tb : treeBranchList){
			if(!tb.toContentObject()){
				logger.error(StringUtils.concat("To ContentObject TreeBranch failed[",tb.genTreePath(),"]"));
				result = false;
			}
		}
		return result;
	}

	@Override
	public TreeBranch createSimpleSubTreeBranch(String pathExp) {
		if(pathExp == null){
			return null;
		}
		String paths[] = pathExp.split("\\.");
		TreeBranch parent = this;
		for(String path : paths){
			StringUtils.StringContainer sc = new StringUtils.StringContainer(path);
			if(!StringUtils.isNullString(sc)){
				TreeBranch atb = parent.getDefaultSubTreeBrancByName(sc.getAfterTrimedString());
				if(atb != null){
					parent = atb;
				}else{
					TreeBranchImp tbi = new TreeBranchImp();
					tbi.setName(sc.getAfterTrimedString());
					try {
						parent.addTreeBranch(tbi);
					} catch (NameAlreadyExistException e) {
						logger.warn(StringUtils.concat(sc.getAfterTrimedString(), " already exist in the tree structure"));
						parent = this.getDefaultSubTreeBrancByName(sc.getAfterTrimedString());
					} catch (AlreadyInTreeStructureException e) {
						//Never go here
						logger.error(e);
						return null;
					}
					parent = tbi;
				}
			}else{
				continue;
			}
		}
		return parent;
	}
	
	@Override
	public void detach(){
		if(this.parent != null){
			this.parent.removeTreeBranch(this);
		}
	}

	@Override
	public synchronized void setTreeBranchName(String name) throws NameIsNullException, DefaultSameNameTreeBranchAlreadyExist {
		this.setName(name);
	}
	
	@Override
	public synchronized void setName(String name) throws NameIsNullException, DefaultSameNameTreeBranchAlreadyExist{
		StringUtils.StringContainer sc = new StringUtils.StringContainer(name);
		if(StringUtils.isNullString(sc)){
			throw new NameIsNullException();
		}
		if(this.parent == null){
			super.setName(sc.getAfterTrimedString());
		}else{
			if(this.getTreeBranchName() != null && this.getTreeBranchName().equals(sc.getAfterTrimedString())){
				return;
			}			
			synchronized(this.parent.treeBranch_initflag){
				if(this.getTreeBranchKind() == null){
					this.parent.changeDefaultSubTreeBranchName(this, sc.getAfterTrimedString());
				}else{
					this.parent.changeNonDefaultSubTreeBranchName(this, sc.getAfterTrimedString());
				}	
			}
		}
	}

	@Override
	public void setTreeBranchKind(String kind) throws DefaultSameNameTreeBranchAlreadyExist {
		this.setKind(kind);
	}
	
	@Override
	public synchronized void setKind(String kind) {
		if (this.parent == null) {
			StringUtils.StringContainer sc = new StringUtils.StringContainer(
					kind);
			if (StringUtils.isNullString(sc)) {
				super.setKind(null);
			} else {
				super.setKind(sc.getAfterTrimedString());
			}
		} else {
			boolean resetKind = false;
			boolean newIsNull = false;
			boolean oldIsNull = false;
			TreeBranchImp parent = this.getParent();
			String oldKind = this.getKind();
			StringUtils.StringContainer sc = new StringUtils.StringContainer(
					kind);
			if (StringUtils.isNullString(sc)) {
				newIsNull = true;
				if (oldKind == null) {
					oldIsNull = true;
					return;
				} else {
					oldIsNull = false;
					resetKind = true;
				}
			} else {
				String realKind = sc.getAfterTrimedString();
				if (oldKind == null) {
					oldIsNull = true;
					resetKind = true;
				} else {
					oldIsNull = false;
					if (!realKind.equals(oldKind)) {
						resetKind = true;
					} else {
						return;
					}
				}
			}
			if (resetKind) {
				synchronized(parent.treeBranch_initflag){
					if(newIsNull){
						TreeBranch oldTreeBranch = parent.getDefaultSubTreeBrancByName(this.getName());
						if(oldTreeBranch != null){
							throw new DefaultSameNameTreeBranchAlreadyExist(StringUtils.concat("Default TreeBranch[",this.genTreePath(),"] already exists"));
						}
					}
					boolean result = false;
					if(newIsNull){
						result = true;
					}else{
						if(oldIsNull){
							result = parent.moveFromDefaultBranchMap(this);
						}else{
							result = true;
						}
					}
					if(result){
						if (newIsNull) {
							super.setKind(null);
						} else {
							super.setKind(sc.getAfterTrimedString());
						}
						if(newIsNull){
							result = parent.moveIntoDefaultBranchMap(this);
						}else{
							result = true;
						}
						if(!result){
							logger.fatal(StringUtils.concat("[TreeBranch][MOVE INTO][",this.genTreePath(),"] set kind from [",this.getKind(),"] to [",kind,"] failed bug"));
						}
					}else{
						logger.fatal(StringUtils.concat("[TreeBranch][MOVE OUT][",this.genTreePath(),"] set kind from [",this.getKind(),"] to [",kind,"] failed bug"));
					}
				}
			}
		}
	}
	
	private boolean moveFromDefaultBranchMap(TreeBranch treeBranch){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		if(treeBranch == null){
			return false;
		}
		if(treeBranch.getTreeBranchKind() != null){
			return false;
		}
		
		TreeBranch tb = this.treeBranchOneMap.get(treeBranch.getTreeBranchName());
		if(tb == null){
			return false;
		}
		if(tb != treeBranch){
			return false;
		}
		TreeBranch tb2 = this.treeBranchOneMap.remove(treeBranch.getTreeBranchName());
		if(tb2 == null){
			return false;
		}
		if(tb2 != treeBranch){
			logger.fatal(StringUtils.concat("moveFromDefaultBranchMap treeBranch[",treeBranch.genTreePath(),"] bug"));
			return false;
		}
		return true;
	}
	
	private boolean moveIntoDefaultBranchMap(TreeBranch treeBranch){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		if(treeBranch == null){
			return false;
		}
		if(treeBranch.getTreeBranchKind() != null){
			return false;
		}
		if(this.treeBranchOneMap.containsKey(treeBranch.getTreeBranchName())){
			return false;
		}
		if(!this.treeBranchList.contains(treeBranch)){
			return false;
		}
		this.treeBranchOneMap.put(treeBranch.getTreeBranchName(), treeBranch);
		return true;
	}

	boolean moveFromDefaultLeafMap(TreeLeaf treeLeaf){
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		if(treeLeaf == null){
			return false;
		}
		if(treeLeaf.getTreeLeafKind() != null){
			return false;
		}
		
		TreeLeaf tl = this.treeLeafOneMap.get(treeLeaf.getTreeLeafName());
		if(tl == null){
			return false;
		}
		if(tl != treeLeaf){
			return false;
		}
		TreeLeaf tl2 = this.treeLeafOneMap.remove(treeLeaf.getTreeLeafName());
		if(tl2 == null){
			return false;
		}
		if(tl2 != treeLeaf){
			logger.fatal(StringUtils.concat("moveFromDefaultLeafMap treeBranch[",treeLeaf.genTreePath(),"] bug"));
			return false;
		}
		return true;
	}
	
	boolean moveIntoDefaultLeafMap(TreeLeaf treeLeaf){
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		if(treeLeaf == null){
			return false;
		}
		if(treeLeaf.getTreeLeafKind() != null){
			return false;
		}
		if(this.treeLeafOneMap.containsKey(treeLeaf.getTreeLeafName())){
			return false;
		}
		if(!this.treeLeafList.contains(treeLeaf)){
			return false;
		}
		this.treeLeafOneMap.put(treeLeaf.getTreeLeafName(), treeLeaf);
		return true;
	}

	@Override
	public String getTreeBranchName() {
		return super.getName();
	}
	
	private void changeMyName(String name){
		super.setName(name);
	}
	
	private boolean changeDefaultSubTreeBranchName(TreeBranch treeBranch, String name) throws DefaultSameNameTreeBranchAlreadyExist{
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		if(treeBranch == null || name == null){
			return false;
		}
		/*
		StringUtils.StringContainer sc = new StringUtils.StringContainer(name);
		if(StringUtils.isNullString(sc)){
			return false;
		}
		*/
		if(treeBranch.getTreeBranchKind() != null){
			return false;
		}
		/*
		if(treeBranch.getTreeBranchName().equals(sc.getAfterTrimedString())){
			return true;
		}
		*/
		TreeBranch temp = this.treeBranchOneMap.get(treeBranch.getTreeBranchName());
		if(temp != treeBranch){
			return false;
		}
		TreeBranch temp2 = this.treeBranchOneMap.get(name);
		if(temp2 != null){
			throw new DefaultSameNameTreeBranchAlreadyExist(StringUtils.concat("[",this.genTreePath(),"][",name,"]"));
		}
		TreeBranch removedObject = this.treeBranchOneMap.remove(treeBranch.getTreeBranchName());
		if(removedObject == null || removedObject != treeBranch){
			//In theory, such thing will never happen, but we put a log here.
			logger.fatal(StringUtils.concat("changeDefaultSubTreeBranchName [",treeBranch.genTreePath(),"] removedObject[",String.valueOf(removedObject),"] is not the original object[",String.valueOf(treeBranch),"]"));
		}
		List<TreeBranch> oldList = this.treeBranchManyMap.get(treeBranch.getTreeBranchName());
		if(oldList == null){
			logger.fatal(StringUtils.concat("changeDefaultSubTreeBranchName [",treeBranch.genTreePath(),"] doesn't in the manyMap"));
		}else{
			boolean removedResult = oldList.remove(treeBranch);
			if(!removedResult){
				logger.fatal(StringUtils.concat("changeDefaultSubTreeBranchName [",treeBranch.genTreePath(),"] removed from the manyMap failed"));
			}
			if(oldList.isEmpty()){
				List<TreeBranch> removedList = this.treeBranchManyMap.remove(treeBranch.getTreeBranchName());
				if(removedList == null || !removedList.isEmpty()){
					logger.fatal(StringUtils.concat("changeDefaultSubTreeBranchName [",treeBranch.genTreePath(),"] removed from the manyMap failed null or is not empty list[",String.valueOf(removedList),"]"));
				}
			}
		}		
		
		((TreeBranchImp)treeBranch).changeMyName(name);
		this.treeBranchOneMap.put(name, treeBranch);
		List<TreeBranch> newList = this.treeBranchManyMap.get(name);
		if(newList == null){
			newList = new ArrayList<TreeBranch>();
			this.treeBranchManyMap.put(name, newList);
		}
		newList.add(treeBranch);
		return true;
	}
	
	private boolean changeNonDefaultSubTreeBranchName(TreeBranch treeBranch, String name){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		if(treeBranch == null || name == null){
			return false;
		}
		/*
		StringUtils.StringContainer sc = new StringUtils.StringContainer(name);
		if(StringUtils.isNullString(sc)){
			return false;
		}
		*/
		if(treeBranch.getTreeBranchKind() == null){
			return false;
		}
		/*
		if(treeBranch.getTreeBranchName().equals(sc.getAfterTrimedString())){
			return true;
		}
		*/
		List<TreeBranch> tempList = this.treeBranchManyMap.get(treeBranch.getTreeBranchName());
		if(tempList == null || tempList.isEmpty() || !tempList.contains(treeBranch)){
			return false;
		}
		
		boolean removedResult = tempList.remove(treeBranch);
		if(!removedResult){
			//In theory, such thing will never happen, but we put a log here.
			logger.fatal(StringUtils.concat("chnageDefaultSubTreeBranchName [",treeBranch.genTreePath(),"] removedResult[",String.valueOf(removedResult),"] is not the original object[",String.valueOf(treeBranch),"]"));
		}
		((TreeBranchImp)treeBranch).changeMyName(name);
		
		List<TreeBranch> tempListNew = this.treeBranchManyMap.get(name);
		if(tempListNew == null){
			tempListNew = new ArrayList<TreeBranch>();
			this.treeBranchManyMap.put(name, tempListNew);
		}
		tempListNew.add(treeBranch);
		return true;
	}
	
	boolean changeDefaultTreeLeafName(TreeLeaf treeLeaf, String name) throws DefaultSameNameTreeLeafAlreadyExist{
		if(!treeLeaf_initflag){
			initDataTreeLeaf();
		}
		if(treeLeaf == null || name == null){
			return false;
		}
		/*
		StringUtils.StringContainer sc = new StringUtils.StringContainer(name);
		if(StringUtils.isNullString(sc)){
			return false;
		}
		*/
		if(treeLeaf.getTreeLeafKind() != null){
			return false;
		}
		/*
		if(treeBranch.getTreeBranchName().equals(sc.getAfterTrimedString())){
			return true;
		}
		*/
		TreeLeaf temp = this.treeLeafOneMap.get(treeLeaf.getTreeLeafName());
		if(temp != treeLeaf){
			return false;
		}
		TreeLeaf temp2 = this.treeLeafOneMap.get(name);
		if(temp2 != null){
			throw new DefaultSameNameTreeLeafAlreadyExist(StringUtils.concat("[",this.genTreePath(),"][",name,"]"));
		}
		TreeLeaf removedObject = this.treeLeafOneMap.remove(treeLeaf.getTreeLeafName());
		if(removedObject == null || removedObject != treeLeaf){
			//In theory, such thing will never happen, but we put a log here.
			logger.fatal(StringUtils.concat("changeDefaultTreeLeafName [",treeLeaf.genTreePath(),"] removedObject[",String.valueOf(removedObject),"] is not the original object[",String.valueOf(treeLeaf),"]"));
		}
		List<TreeLeaf> oldList = this.treeLeafManyMap.get(treeLeaf.getTreeLeafName());
		if(oldList == null){
			logger.fatal(StringUtils.concat("changeDefaultTreeLeafName [",treeLeaf.genTreePath(),"] doesn't in the manyMap"));
		}else{
			boolean removedResult = oldList.remove(treeLeaf);
			if(!removedResult){
				logger.fatal(StringUtils.concat("changeDefaultTreeLeafName [",treeLeaf.genTreePath(),"] removed from the manyMap failed"));
			}
			if(oldList.isEmpty()){
				List<TreeLeaf> removedList = this.treeLeafManyMap.remove(treeLeaf.getTreeLeafName());
				if(removedList == null || !removedList.isEmpty()){
					logger.fatal(StringUtils.concat("changeDefaultTreeLeafName [",treeLeaf.genTreePath(),"] removed from the manyMap failed null or is not empty list[",String.valueOf(removedList),"]"));
				}
			}
		}		
		
		((TreeLeafImp)treeLeaf).changeMyName(name);
		this.treeLeafOneMap.put(name, treeLeaf);
		List<TreeLeaf> newList = this.treeLeafManyMap.get(name);
		if(newList == null){
			newList = new ArrayList<TreeLeaf>();
			this.treeLeafManyMap.put(name, newList);
		}
		newList.add(treeLeaf);
		return true;
	}
	
	boolean changeNonDefaultTreeLeafName(TreeLeaf treeLeaf, String name){
		if(!treeBranch_initflag){
			initDataTreeBranch();
		}
		if(treeLeaf == null || name == null){
			return false;
		}
		/*
		StringUtils.StringContainer sc = new StringUtils.StringContainer(name);
		if(StringUtils.isNullString(sc)){
			return false;
		}
		*/
		if(treeLeaf.getTreeLeafKind() == null){
			return false;
		}
		/*
		if(treeBranch.getTreeBranchName().equals(sc.getAfterTrimedString())){
			return true;
		}
		*/
		List<TreeLeaf> tempList = this.treeLeafManyMap.get(treeLeaf.getTreeLeafName());
		if(tempList == null || tempList.isEmpty() || !tempList.contains(treeLeaf)){
			return false;
		}
		
		boolean removedResult = tempList.remove(treeLeaf);
		if(!removedResult){
			//In theory, such thing will never happen, but we put a log here.
			logger.fatal(StringUtils.concat("changeNonDefaultTreeLeafName [",treeLeaf.genTreePath(),"] removedResult[",String.valueOf(removedResult),"] is not the original object[",String.valueOf(treeLeaf),"]"));
		}
		((TreeLeafImp)treeLeaf).changeMyName(name);
		
		List<TreeLeaf> tempListNew = this.treeLeafManyMap.get(name);
		if(tempListNew == null){
			tempListNew = new ArrayList<TreeLeaf>();
			this.treeLeafManyMap.put(name, tempListNew);
		}
		tempListNew.add(treeLeaf);
		return true;
	}
}
